var xmppServerAddress = "10.69.173.4";
var boshUrl = "http://" + xmppServerAddress + ":5280/http-bind";
var xmppConnection = null;
var subscriber = null;
var alias = 'alice';

window.addEventListener('load', connect);

window.addEventListener('unload', disconnect);

$(document).on('dblclick', '.chatContact, .groupchatContact', function (event) {
	var id = event.target.id;
	var label = event.target.label;
	var tabId = 'tab' + id;
	var panelId = 'panel' + id;
	var inputId = 'input' + id;
	var conversationId = 'conversation' + id;
	var notificationId = 'notification' + id;
	var index = 0;
	var tabsChat = document.getElementById('tabsChat');
	var count = tabsChat.itemCount;
	if ($('#' + tabId).length === 0) {
		/** L'onglet n'existe pas encore */
		index = count;
		$('#tabsChat tab').removeAttr('selected');
		/** Créer la zone de saisie, la zone de messages */
		$('#tabpanelsChat').append('<tabpanel id="' + panelId + '"><vbox><textbox id="' + conversationId + '" class="conversation" multiline="true" readonly="true" /><label id="' + notificationId + '" class="notification" /><html:input xmlns:html="http://www.w3.org/1999/xhtml" type="text" class="message" id="' + inputId + '" /></vbox></tabpanel>');
		/** Ajouter l'onglet correspondant au contact double-cliqué */
		$('#tabsChat').append('<tab oncommand="tabSelected(this);" id="' + tabId + '" label="' + label + '" linkedpanel="' + panelId + '" />');
		var groupchat = $(this).hasClass('groupchatContact');
		var jid;
		if (groupchat) {
			jid = id + '@conference.' + xmppServerAddress;
		} else {
			jid = id + '@' + xmppServerAddress;
		}
		$('#' + inputId).data({
			jid: jid,
			groupchat: groupchat
		});
	} else {
		/** Si l'onglet existe déjà on récupère son index */
		var tab = document.getElementById(tabId);
		index = tabsChat.getIndexOfItem(tab);
	}
	if (index > 0) {
		// Bug de Thunderdird ??
		var tabboxChat = document.getElementById('tabboxChat');
		tabboxChat.selectedIndex = index;
	}
	$('#' + panelId + ' .message').focus();
	document.getElementById('popupChat').openPopupAtScreen(200, 200, false);
});

$(document).on('keypress', '.message', function (event) {
	var inputId = event.target.id;
	if (event.which == 13) {
		/** Si l'utilisateur appuie sur Entrée, envoyer le message */
		event.preventDefault();
		var groupchat = $('#' + inputId).data('groupchat');
		if (groupchat) {
			sendMessage(inputId, 'groupchat');
		} else {
			sendMessage(inputId, 'chat');
		}
	} else {
		/** Sinon envoyer une notification que l'utilisateur est en train de taper */
		var jid = $('#' + inputId).data('jid');
		var notify = $msg({to: jid, type: 'chat'}).c('composing', {xmlns: 'http://jabber.org/protocol/chatstates'});
		xmppConnection.send(notify);
	}
});

$(document).bind('connect', function (event, data) {
	xmppConnection = new Strophe.Connection(boshUrl);
	xmppConnection.connect(data.jid, data.password, function (status) {
		switch (status) {
			case Strophe.Status.CONNECTING : {
				$('#xmppStatus').val('Veuillez patienter...');
				break;
			}
			case Strophe.Status.CONNECTED : {
				$('#xmppStatus').val('Connecté au serveur XMPP');
				$(document).trigger('connected');
				break;
			}
			case Strophe.Status.DISCONNECTING : case Strophe.Status.DISCONNECTED : {
				$('#xmppStatus').val('Déconnecté du serveur XMPP');
				$(document).trigger('disconnected');
				break;
			}
			case Strophe.Status.AUTHFAIL : case Strophe.Status.CONNFAIL : case Strophe.Status.ERROR : {
				$('#xmppStatus').val('Connexion au serveur XMPP échouée');
				break;
			}
			default : {
				$('#xmppStatus').val(status);
				break;
			}
		}
	});
});

$(document).bind('connected', function (event, data) {
	/** Utilisateur vient de se connecter au serveur */
	$('#addContactCmd').removeAttr('disabled');
	
	/** Demander la liste de contacts */
	var iq = $iq({type : 'get'}).c('query', {xmlns : Strophe.NS.ROSTER});
	xmppConnection.sendIQ(iq, rostersReceived);
	
	xmppConnection.addHandler(messageReceived, null, 'message', 'chat');
});

$(document).bind('disconnected', function (event, data) {
	xmppConnection = null;
	$('#contacts listitem').remove();
	$('#addContactCmd').attr('disabled', 'true');
});

function connect() {
	$(document).trigger('connect', {jid: alias + '@' + xmppServerAddress + '/fidumail', password: alias});
};

function disconnect() {
	xmppConnection.disconnect();
	xmppConnection = null;
};

function rostersReceived(iq) {
	/** Liste de contacts reçue de la part du serveur XMPP */
	$(iq).find('item').each(function (i) {
		var jid = Strophe.getBareJidFromJid($(this).attr('jid'));
		var userId = Strophe.getNodeFromJid(jid);
		var name = $(this).attr('name') || jid;
		/** Pour chaque contact, préparer la balise <listitem> et l'insérer dans la zone des contacts */
		var contact = $('<listitem />');
		contact.attr({
			label: name,
			tooltiptext: jid,
			jid: jid,
			id: userId,
			value: jid,
			image: 'chrome://sip/content/img/offline-icon.png',
			context: 'popupContact'
		});
		contact.addClass('listitem-iconic').addClass('offline');
		$('#contacts').append(contact);
	});
	
	xmppConnection.addHandler(presenceReceived, null, 'presence');
	xmppConnection.addHandler(rostersChanged, Strophe.NS.ROSTER, 'iq', 'set');
	
	/** Signaler à tous les contacts qu'on vient de se connecter */
	xmppConnection.send($pres());
	$(document).trigger('rostersReceived');
};

function presenceReceived(presence) {
	/** le serveur vient d'envoyer une balise <presence>, i.e un des contacts vient de changer son statut de présence */
	var from = Strophe.getBareJidFromJid($(presence).attr('from'));
	var userId = Strophe.getNodeFromJid(from);
	var type = $(presence).attr('type');
	
	if (type === 'subscribe') {
		/** quelqu'un veut ajouter l'utilisateur à la liste d'amis */
		subscriber = from;
		var label = from + ' souhaite vous ajouter à sa liste d\'amis.';
		$('#popupApproveContact label').val(label);
		document.getElementById('popupApproveContact').openPopupAtScreen(200, 200, false);
	} else if (type === 'unsubscribe' || type === 'unsubscribed') {
		removeContact(from);
	} else if (type !== 'error') {
		var contact = $('#' + userId);
		contact.removeClass('online offline away dnd');
		
		if (type === 'unavailable') {
			/** le contact est déconnecté */
			contact.removeClass('chatContact');
			contact.addClass('offline');
			contact.attr({
				tooltiptext: 'Déconnecté',
				image: 'chrome://sip/content/img/offline-icon.png'
			});
		} else {
			/** le contact est connecté */
			contact.addClass('chatContact');
			var show = $(presence).find('show').text();
			switch (show) {
				case 'away' : case 'xa' : {
					/** le contact connecté, mais pas devant son ordinateur */
					contact.addClass('away');
					contact.attr({
						tooltiptext: 'Ailleurs',
						image: 'chrome://sip/content/img/away-icon.png'
					});
					break;
				}
				case 'dnd' : {
					/** le contact connecté, mais ne veut pas discuter */
					contact.addClass('dnd');
					contact.attr({
						tooltiptext: 'Ne pas déranger',
						image: 'chrome://sip/content/img/busy-icon.png'
					});
					break;
				}
				default : {
					/** le contact connecté et prêt à discuter */
					contact.addClass('online');
					contact.attr({
						tooltiptext: 'Disponible',
						image: 'chrome://sip/content/img/online-icon.png'
					});
					break;
				}
			}
		}
	}
	return true;
};

function rostersChanged(iq) {
	$(iq).find('item').each(function () {
		var jid = Strophe.getBareJidFromJid($(this).attr('jid'));
		var userId = Strophe.getNodeFromJid(jid);
		var name = $(this).attr('name') || jid;
		var subscription = $(this).attr('subscription');
		var currentContact = $('#' + userId);
		
		if (subscription === 'remove') {
			currentContact.remove();
		} else {
			var classes = currentContact.attr('class') || 'offline';
			var icon = currentContact.attr('image') || 'chrome://sip/content/img/offline-icon.png';
			var newContact = $('<listitem />');
			newContact.attr('class', classes);
			newContact.addClass('listitem-iconic');
			newContact.attr({
				label: name,
				id: userId,
				tooltiptext: jid,
				jid: jid,
				image: icon,
				value: jid,
				context: 'popupContact'
			});
			if (currentContact.length > 0) {
				/** Si le contact existe déjà on le remplace */
				currentContact.replaceWith(newContact);
			} else {
				/** Sinon on ajoute le nouveau */
				$('#contacts').append(newContact);
			}
		}
	});
	return true;
};

function showPopupAddContact() {
	document.getElementById('popupAddContact').openPopupAtScreen(200, 200, false);
};

function addContact() {
	document.getElementById('popupAddContact').hidePopup();
	var jidContact = $('#jidContact').val();
	var nameContact = $('#nameContact').val();
	if (jidContact && nameContact) {
		/** Ajouter le contact dans la liste */
		var iq = $iq({type : 'set'}).c('query', {xmlns : Strophe.NS.ROSTER}).c('item', {jid: jidContact, name: nameContact});
		/** Puis demander de connaître sa présence */
		var subscribe = $pres({to: jidContact, type: 'subscribe'});
		xmppConnection.sendIQ(iq);
		xmppConnection.send(subscribe);
	}
	$('#jidContact').val('');
	$('#nameContact').val('');
};

/** Supprimer un contact à partir d'un menu contextuel (popup menu) */
function deleteContact() {
	/** Récupérer le contact sélectionné et son jid */
	var contact = document.getElementById('contacts').selectedItem;
	var jid = contact.getAttribute('jid');
	/** Le supprimer de la liste */
	removeContact(jid);
};

/** Supprimer un contact sachant son jid */
function removeContact(jid) {
	/** Message presence indiquant au serveur qu'on ne veut plus suivre le statut de présence de ce contact */
	var presence = $pres({to: jid, type: 'unsubscribe'});
	/** Message iq indiquant au serveur de supprimer ce contact de la liste de contacts */
	var iq = $iq({type: 'set'}).c('query', {xmlns: Strophe.NS.ROSTER}).c('item', {jid: jid, subscription: 'remove'});
	xmppConnection.send(presence);
	xmppConnection.sendIQ(iq);
};

/** Accepter une personne de m'ajouter dans sa liste de contacts */
function approveContact() {
	document.getElementById('popupApproveContact').hidePopup();
	var approve = $pres({to: subscriber, type: 'subscribed'});
	xmppConnection.send(approve);
	var userId = Strophe.getNodeFromJid(subscriber);
	if ($('#' + userId).length === 0) {
		$('#jidContact').val(subscriber);
		showPopupAddContact();
	}
	subscriber = null;
};

/** Refuser une personne de m'ajouter dans sa liste de contacts */
function denyContact() {
	document.getElementById('popupApproveContact').hidePopup();
	var deny = $pres({to: subscriber, type: 'unsubscribed'});
	xmppConnection.send(deny);
	subscriber = null;
};

/** Envoyer un message à l'interlocuteur.
  * messageType = chat : discussion deux à deux.
  * messageType = groupchat : discussion dans un chatroom.
  */
function sendMessage(inputId, messageType) {
	var inputElement = $('#' + inputId);
	var jid = inputElement.data('jid');
	var userId = Strophe.getNodeFromJid(jid);
	var message = inputElement.val();
	if (message !== '') {
		var msg = $msg({
			to: jid,
			type: messageType
		}).c('body').t(message);
		xmppConnection.send(msg);
		writeMessage(jid, userId, 'Moi', message);
		inputElement.val('');
	}
};

/** Ecrire les messages chat dans la zone des messages */
function writeMessage(jid, id, name, message) {
	if (message !== null && message !== '') {
		var conversation = $('#conversation' + id).val();
		if (conversation !== '') {
			$('#conversation' + id).val(conversation + '\n\n' + name + ' : ' + message);
		} else {
			$('#conversation' + id).val(name + ' : ' + message);
		}
	}
};

function messageReceived(message) {
	var jid = Strophe.getBareJidFromJid($(message).attr('from'));
	var userId = Strophe.getNodeFromJid(jid);
	var contact = document.getElementById(userId);
	var name = contact.label;
	
	var composing = $(message).find('composing');
	if (composing.length > 0) {
		/** La présence d'une balise <composing /> indique une notification */
		$('#notification' + userId).val(name + ' est en train de taper...');
		return true;
	}
	
	var body = $(message).find('body');
	if (body.length > 0) {
		body = body.text();
		/** L'interlocuteur vient d'envoyer un message, on supprime la notification */
		$('#notification' + userId).val('');
		/** Ouvrir l'onglet de chat si ce n'est pas encore ouvert */
		$('#' + userId).dblclick();
	} else {
		body = null;
	}
	writeMessage(jid, userId, name, body);
	return true;
};

/** Changer le statut de présence : disponible, absent, ne pas déranger */
function changeStatus(event) {
	var show = event.target.value;
	if (show === 'offline') {
		disconnect();
		return;
	}
	if (!xmppConnection) {
		/** On se connecte si c'est pas le cas */
		$(document).one('rostersReceived', function () {
			var presence = $pres().c('show').t(show);
			xmppConnection.send(presence);
		});
		connect();
		return;
	}
	/** Si c'est déjà connecté, envoyer simplement un message de présence : 
	  * prêt à discuter, ne pas déranger ou absent.
	  */
	var presence = $pres().c('show').t(show);
	xmppConnection.send(presence);
};

function openChatTab() {
	var contact = document.getElementById('contacts').selectedItem;
	var id = contact.id;
	$('#' + id).dblclick();
};

function closeChatTab() {
	var tabsChat = document.getElementById('tabsChat');
	var tabboxChat = document.getElementById('tabboxChat');
	var index = tabsChat.selectedIndex;
	if (index > -1) {
		deleteMessages();
		var idTab = tabboxChat.selectedTab.id;
		$('#' + idTab).remove();
	}
	if (tabsChat.itemCount === 0) {
		/** Si le dernier onglet vient d'être fermé, on ferme toute la fenêtre */
		document.getElementById('popupChat').hidePopup();
	}
	if (tabsChat.itemCount === index) {
		/** Si dernier onglet, on passe à l'onglet précédent */
		tabboxChat.selectedIndex = index - 1;
	} else {
		/** Sinon on passe à l'onglet suivant */
		tabboxChat.selectedIndex = index;
	}
};

function deleteMessages() {
	var tabboxChat = document.getElementById('tabboxChat');
	var idPanel = tabboxChat.selectedPanel.id;
	$('#' + idPanel + ' .conversation').val('');
};

function tabSelected(tab) {
	var panelId = tab.linkedPanel;
	$('#' + panelId + ' .message').focus();
};

function joinChatRoom() {
	document.getElementById('popupJoinChatRoom').hidePopup();
	
	var room = $('#jidChatRoom').val();
	var jid = room + '@conference.' + xmppServerAddress + '/' + alias;
	var presence = $pres({to: jid}).c('x', {xmlns : Strophe.NS.MUC});
	xmppConnection.send(presence);
	
	var contact = $('<listitem />');
	contact.attr({
		label: room,
		tooltiptext: jid,
		jid: jid,
		id: room,
		value: jid,
		image: 'chrome://sip/content/img/online-icon.png',
		context: 'popupContact'
	});
	contact.addClass('groupchatContact listitem-iconic online');
	$('#contacts').append(contact);
	contact.dblclick();
};

function showPopupJoinChatRoom() {
	document.getElementById('popupJoinChatRoom').openPopupAtScreen(200, 200, false);
};
